package org.dreamwork.cai.srf;

import org.dreamwork.cai.SRFException;
import org.dreamwork.cai.tools.Const;
import org.dreamwork.concurrent.broadcast.ILocalBroadcastService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务路由表.
 *
 * <pre>
 * Service Route Table
 * +- Service Route Frame
 * |  +- Service Route Item
 * |  +- SRI
 * |  +- ...
 * +- SRF
 * +- ...
 * </pre>
 * 其中
 * <ul>
 *     <li>每一个 SRF 代表一个节点，其中 {@code local} 代表本地节点</li>
 *     <li>每一个 SRI 代表节点下的一个 {@code interface}</li>
 * </ul>
 * 可以使用 {@code SRT.get (namespace).get (itemName)} 来索引一个服务，并调用
 */
public class ServiceRouteTable implements Serializable {
    public final Map<String, ServiceRouteFrame> frames = Collections.synchronizedMap (new HashMap<> ());
    private transient final Map<String, ServiceRouteFrame> mappedByKey = Collections.synchronizedMap (new HashMap<> ());
    private transient final Logger logger = LoggerFactory.getLogger (ServiceRouteTable.class);
    private transient ILocalBroadcastService broadcaster;

    public void setBroadcaster (ILocalBroadcastService broadcaster) {
        this.broadcaster = broadcaster;
    }

    /**
     * 向路由表中添加一个 {@code SRF}
     * @param frame SRF
     * @throws SRFException 如果纯在同名的SRF则抛出错误
     */
    public void add (ServiceRouteFrame frame) throws SRFException {
        if (frames.containsKey (frame.namespace)) {
            throw new SRFException ("namespace: " + frame.namespace + " already exists.");
        }

        frames.put (frame.namespace, frame);
//        mappedByKey.put (frame.host, frame);
        mappedByKey.put (frame.host + ":" + frame.udpPort, frame);

        if (logger.isTraceEnabled ()) {
            logger.trace ("a srf added, broadcast it via {}", broadcaster);
        }
        if (broadcaster != null)
            broadcaster.broadcast (Const.Category.CAT_SRF_EVENT, Const.SRF.UPDATE, frame);
    }

    public synchronized void remove (ServiceRouteFrame frame) {
        if (frame != null) {
            frames.remove (frame.namespace);
            mappedByKey.remove (frame.host + ":" + frame.udpPort);

            if (logger.isTraceEnabled ()) {
                logger.trace ("a srf removed, broadcast it via {}", broadcaster);
            }
            if (broadcaster != null)
                broadcaster.broadcast (Const.Category.CAT_SRF_EVENT, Const.SRF.WITHDRAWN, frame);
        }
    }

    public synchronized void removeByHost (String host, int port) {
        ServiceRouteFrame srf = getByHost (host, port);
        if (srf != null) {
            remove (srf);
        }
    }

    public synchronized void remove (String namespace) {
        ServiceRouteFrame srf = get (namespace);
        if (srf != null) {
            remove (srf);
        }
    }

    /**
     * 根据给定的 {@code namespace} 来索引一个 {@code SRF}
     * @param namespace SRF的命名空间
     * @return SRF
     */
    public synchronized ServiceRouteFrame get (String namespace) {
        return frames.get (namespace);
    }

    public synchronized ServiceRouteFrame getByHost (String host, int port) {
        return mappedByKey.get (host + ":" + port);
    }
}